package BST;

import java.util.ArrayList;

/*
 * 
 * This class provides all the functionalities requested.
 * Per functionality there is a method
 * The description above each method specifies the related Command
 * 
 */

public class BinaryTree {
	private int min = -1;
	private int max = -1;
	private int size = 0;
	private int total = 0;

	private Node root = null;
	private Node current = null;


	private Iterator iterator;

	public BinaryTree(){	
		iterator = new Iterator();
	}

	//For the ContainsCommand
	public boolean search(int number){
		Node current = root;
		while(current!=null){
			if(number < current.getLeft().getValue()){
				current = current.getLeft();
			} else if(number > current.getRight().getValue()){
				current = current.getRight();
			} else {
				return true;//Found the incoming number in the tree
			}
		}
		return false;
	}

	public int inversedSuccessive(int i) {
		
		ArrayList<Integer> list = new ArrayList<Integer>();
		list = this.getSeqList();
		
		Integer value = -1;
		
		for (int i2 = 0; i2 < list.size(); i2 ++) {
			if (list.get(i2) == i) {
				if (i2>0) {
					value = list.get(i2-1);
				}
			}
		}
		
		return value;			
	}
	
	public int successive(int i) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		list = this.getSeqList();
		
		Integer value = -1;
		
		for (int i2 = 0; i2 < list.size(); i2 ++) {
			if (list.get(i2) == i) {
				if (i2 < list.size()-1) {
					value = list.get(i2+1);
				}
			}
		}
		
		return value;						
	}



	//For the InsertCommand
	//And the RedoCommand
	public boolean insert(int number){		
		if(root == null){
			root = new Node();
			root.setValue(number);
		} else{
			current = root;
			Node parent = null;
			while(current != null){
				if(current.getValue() != -1){
					if(number < current.getValue()){
						parent = current;
						current = current.getLeft();
					} else if(number > current.getValue()){
						parent = current;
						current = current.getRight();
					} else {
						return false; //Number already in the tree
					}
				} else {				
					break;
				}
			}			
			if(number < parent.getValue()){
				Node node = new Node();					
				node.setValue(number);			
				parent.setLeft(node);				
			} else if(number > parent.getValue()){
				Node node = new Node();
				node.setValue(number);				
				parent.setRight(node);
			}
		}		
		size++;
		total += number;
		return true; 
	}

	
	public boolean delete (Integer number) {
		boolean result = false;
		ArrayList<Integer> tree = this.getSeqList();
		
		for (int i = 0; i < tree.size(); i++) {
			if (number.equals(tree.get(i))) {
				tree.remove(i);
				result = true;
			}

		}
		// clear tree
		
		this.clear();
		
		// rebuild tree
		
		this.insertArray(tree);
		
		return result;
	}
	
	public boolean contains(Integer number) {
		boolean result = false;
		ArrayList<Integer> tree = this.getSeqList();
		
		for (int i = 0; i < tree.size(); i ++) {
			if (number.equals(tree.get(i))) {
				result = true;
				break;
			}
		}
		
		return result;
	}


	//For the InsertArrayCommand
	public boolean insertArray(ArrayList<Integer> array){	
		for (Integer i : array) {
			this.insert(i);
		}
		return true;
	}

	public boolean insertAndDestroyArray(ArrayList<Integer> array) {
		while (!array.isEmpty()) {
			this.insert(array.remove(0));
		}

		return true;
	}

	//For the ListCommand
	//This uses the iterator and the recursion.
	//This fulfills the use of the COMPOSITE PATTERN and the Iterator
	public ArrayList<Integer> getSeqList(){
		return iterator.getList(root);
	}


	//For the MaxCommand
	public int getMaxValue(){		
		return maxValue(this.root);
	}

	public int maxValue(Node node){
		if(root != null){
			if(node.getRight().getValue() != -1){
				this.max= maxValue(node.getRight());			
			} else{
				this.max = node.getValue();
			}
		} else{
			return -1;		
		}
		return this.max;
	}

	//For the MinCommand
	public int getMinValue(){
		return minValue(this.root);
	}

	public int minValue(Node node){
		if(root != null){			
			if(node.getLeft().getValue() != -1){
				this.min= minValue(node.getLeft());			
			} else{
				this.min = node.getValue();
			}
		} else{
			return -1;
		}		
		return this.min;
	}

	//For the MeanCommand
	public int averageValue(){
		return (int) total/size;		
	}

	//For the number command
	public int getSize(){
		return this.size;
	}

	//For the TotalCommand
	public int getTotal(){
		return this.total;
	}

	//This function clears the whole tree after a commit
	public boolean clear(){
		this.root = null;
		this.current = null;
		this.max = 0;
		this.min = 0;
		this.size = 0;
		this.total = 0;
		return true;
	}


}
